package com.unknow.first.dapp.admin.service.impl;

import static com.unknow.first.dapp.admin.constants.AddressInfoErrorConstants.ADDRESS_UP_BINDED;
import static com.unknow.first.dapp.admin.constants.AddressInfoErrorConstants.ADDRESS_UP_BINDING;
import static com.unknow.first.dapp.admin.constants.AddressInfoErrorConstants.CHILD_PARENT_IS_SAME;
import static com.unknow.first.dapp.admin.constants.AddressInfoErrorConstants.PARENT_ADDRESS_NOT_BIND;
import static com.unknow.first.dapp.admin.constants.AddressInfoErrorConstants.PARENT_ADDRESS_NOT_EXISTS;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.unknow.first.dapp.admin.mapper.TAddressInfo;
import com.unknow.first.dapp.admin.mapper.TAddressInfoMapper;
import com.unknow.first.dapp.admin.service.IBindParentAfter;
import com.unknow.first.dapp.admin.service.TAddressInfoService;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.cloud.core.redis.RedisUtil;
import org.cloud.utils.SpringContextUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * @author Administrator
 * @description 针对表【t_address_info(用户关系关联表)】的数据库操作Service实现
 * @createDate 2022-02-26 12:10:12
 */
@Service
public class TAddressInfoServiceImpl extends ServiceImpl<TAddressInfoMapper, TAddressInfo> implements TAddressInfoService {

    @Override
    public List<TAddressInfo> getTeamTree(String parentAddress, String address) {
        List<TAddressInfo> rs = new ArrayList<>();
        if (!StringUtils.isEmpty(parentAddress) || !StringUtils.isEmpty(address)) {
            QueryWrapper<TAddressInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(!StringUtils.isEmpty(parentAddress), TAddressInfo::getParentAddress, parentAddress)
                .eq(!StringUtils.isEmpty(address), TAddressInfo::getAddress, address);
            rs = getBaseMapper().selectList(queryWrapper);
        }
        return rs;
    }


    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Boolean bind(String parentAddress, String childAddress) throws Exception {

        Assert.isTrue(!parentAddress.equals(childAddress), CHILD_PARENT_IS_SAME.code);

        final String bindLockerName = "address.info.locker." + childAddress;
        Boolean locked = RedisUtil.single().getLock(bindLockerName, 3600L);
        Assert.isTrue(locked, ADDRESS_UP_BINDING.code);

        try {
            LambdaQueryWrapper<TAddressInfo> checkParentAddressQuery = Wrappers.<TAddressInfo>lambdaQuery().eq(TAddressInfo::getAddress, parentAddress);
            Assert.isTrue(baseMapper.selectCount(checkParentAddressQuery) > 0, PARENT_ADDRESS_NOT_EXISTS.code);
            checkParentAddressQuery = checkParentAddressQuery.isNotNull(TAddressInfo::getParentAddress);
            Assert.isTrue(baseMapper.selectCount(checkParentAddressQuery) > 0, PARENT_ADDRESS_NOT_BIND.code);

            LambdaQueryWrapper<TAddressInfo> childAddressQuery = Wrappers.<TAddressInfo>lambdaQuery().eq(TAddressInfo::getAddress, childAddress);
            TAddressInfo childAddressInfo = baseMapper.selectOne(childAddressQuery);
            Assert.isTrue(childAddressInfo == null || !StringUtils.hasLength(childAddressInfo.getParentAddress()), ADDRESS_UP_BINDED.code);
            if (childAddressInfo == null) {
                childAddressInfo = TAddressInfo.builder().address(childAddress).parentAddress(parentAddress).blockTimestamp(new Date()).build();
                baseMapper.insert(childAddressInfo);
            } else {
                childAddressInfo.setParentAddress(parentAddress);
                baseMapper.updateById(childAddressInfo);
            }

            boolean result = baseMapper.bind(parentAddress, childAddress) > 0;

            IBindParentAfter bindParentAfter = SpringContextUtil.getBean(IBindParentAfter.class);

            if (bindParentAfter != null) {
                bindParentAfter.initAddress(parentAddress, childAddress);
            }
            return result;

        } finally {
            RedisUtil.single().releaseLock(bindLockerName);
        }
    }
}